﻿using System;
using System.Collections.Generic;
using Development.Tools;
using System.Configuration;
using System.Threading;


namespace Development.DbData
{
    /// <summary>
    /// 数据库提交对象
    /// </summary>
    public class DbSqlInfo
    {
        public string DbName { get; set; }
        public string Sql { get; set; }
    }
    /// <summary>
    /// 管理dbprovider
    /// </summary>
    public class DbProviderManager : Singleton<DbProviderManager>
    {
        private Dictionary<string, DbProvider> m_dbProviders = new Dictionary<string, DbProvider>();

        private Queue<DbSqlInfo> m_sqlQueue = new Queue<DbSqlInfo>();

        private Dictionary<string, ConnectionStringSettings> m_dbSettings = new Dictionary<string, ConnectionStringSettings>();

        private Thread m_thread = null;    //用来数据修改线程
        private bool m_run = false;

        private DateTime m_lastTime;
        
        /// <summary>
        /// 先检查数据表，然后长连接数据库
        /// </summary>
        /// <returns></returns>
        public bool Init()
        {
            foreach (ConnectionStringSettings connection in ConfigurationManager.ConnectionStrings)
            {
                m_dbSettings.Add(connection.Name, connection);
                DbProvider provider = DbDataHelper.CreateDbProvider(connection);
                if (provider != null)
                {
                    if (provider.Open())
                    {
                        m_dbProviders.Add(connection.Name, provider);
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// 开始起动队列提交线程
        /// </summary>
        public void StartUpdateDb()
        {
            m_thread = new Thread(Worker);
            m_run = true;
            m_thread.Start();
            m_lastTime = DateTime.Now;
            Log.WriteLog(ELogLevel.LOG_INFO, "db thread start success");
        }

        /// <summary>
        /// 项数据库提交工作线程
        /// </summary>
        private void Worker()
        {
            while (m_run)
            {
            
                if(m_sqlQueue.Count != 0)
                {
                    DbSqlInfo info = null;
                    lock (m_sqlQueue)
                    {
                        info = m_sqlQueue.Dequeue();
                    }
                    if(info != null)
                    executeSql(info);
                }
                else
                {
                    Thread.Sleep(500);
                    KeepLive();
                }
            }
            DateTime tempTime = DateTime.Now;
            Log.WriteLog(ELogLevel.LOG_INFO, "db queue count = " + m_sqlQueue.Count);
            while(m_sqlQueue.Count != 0)
            {
                if ((DateTime.Now - tempTime).TotalMinutes >= 1)
                {
                    Log.WriteLog(ELogLevel.LOG_INFO, "db queue count = " + m_sqlQueue.Count);
                    tempTime = DateTime.Now;
                }
                DbSqlInfo info = m_sqlQueue.Dequeue();
                executeSql(info);
            }
            foreach (KeyValuePair<string, DbProvider> db in m_dbProviders)
            {
                db.Value.Close();
            }
            m_dbProviders.Clear();
            Log.WriteLog(ELogLevel.LOG_INFO, "db queue finish count = " + m_sqlQueue.Count);
            Log.WriteLog(ELogLevel.LOG_INFO,"按任意键退出");
            Console.ReadKey();

        }

        /// <summary>
        /// 提交修改
        /// </summary>
        /// <param name="sqlinfo"></param>
        private void executeSql(DbSqlInfo sqlinfo)
        {
            DbProvider provider = GetProvider(sqlinfo.DbName);
            if(provider != null)
            {
                int ret = provider.ExecuteNonQuery(sqlinfo.Sql);
                if(ret == 0)
                {
                    Log.WriteLog(ELogLevel.LOG_ERROR, "sql return zero:" + sqlinfo.Sql);
                }
            }
            else 
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, "not find db:" + sqlinfo.DbName);
            }
        }

        /// <summary>
        /// 增加一个数据库修改
        /// </summary>
        /// <param name="dbName"></param>
        /// <param name="sql"></param>
        public void AddSql(string dbName,string sql)
        {
            DbSqlInfo info = new DbSqlInfo() {DbName = dbName,Sql = sql };
            lock(m_sqlQueue)
            {
                m_sqlQueue.Enqueue(info);
            }
        }

        /// <summary>
        /// 通过名字获取连接者
        /// </summary>
        /// <param name="dbName"></param>
        /// <returns></returns>
        private DbProvider GetProvider(string dbName)
        {
            if (m_dbProviders.ContainsKey(dbName))
            {
                return m_dbProviders[dbName];
            }
            return null;
        }

        /// <summary>
        /// 执行查询
        /// </summary>
        /// <param name="dbName"></param>
        /// <param name="action"></param>
        public void ExecuteQuery(string dbName,Action<DbProvider> action)
        {
            ConnectionStringSettings connection = null;
            if(m_dbSettings.TryGetValue(dbName,out connection))
            {
                DbProvider provider = DbDataHelper.CreateDbProvider(connection);
                if (provider != null)
                {
                    if (provider.Open())
                    {
                        action(provider);
                    }
                    provider.EndExecuteQuery();
                    provider.Close();
                }

            }
            
        }

        /// <summary>
        /// 如果启用的它 就必须在逻辑线程里面调用
        /// </summary>
        /// <param name="dt"></param>
        private void KeepLive()
        {
            if((DateTime.Now - m_lastTime).Hours >= 1 )
            {  
                foreach(KeyValuePair<string,DbProvider> p in m_dbProviders)
                {
                    p.Value.KeepLive();
                }
                m_lastTime = DateTime.Now;
            }
        }


        public void Release()
        {
            m_run = false;
        }
    }
}
